grammar MimicParser;
options {
language=CSharp3;
tokenVocab=MimicLexer;
}
//import MimicLexer;

/*
//dear Walter 

There is a branch that can never be reached. parseDeclarations: else if (t->ty == Tfunction)
will never be true. parse basic type2() never returns Tfunction

In parse statement, following { is it true that an EOF is acceptable over } ?

It appears parse_declarations and Semicolon subrules are follwed by continue; in DMD code
this means parseDeclDef(once=true) would actually allow multiple of these subrules

the web spec is horribly wrong/out of date. perhaps use my antlr grammar?

immutable and shared are D2.0 things, why are they in the 1.0 web spec?
*/

//TODO check all instances of isDeclaration in DMD code. I did not realize it checks for identifier's prescence
//TODO possibly rename rules that arent parse blah() types. make more like walter's web. I think i started doing this around the time of parse statement


//the starting point for all files
//start parse_module
parse_module
	:	moduleDeclaration? parse_decl_defs
	;

moduleDeclaration
	:	Module moduleFullyQualifiedName Semicolon
	;

moduleFullyQualifiedName
	:	(packages Dot)? moduleName
	;

moduleName
	:	Identifier
	;

//TODO will the greedy * allow moduleName to match at the end?
packages
	:	packageName (Dot packageName)*
	;

packageName
	:	Identifier
	;
//end parse_module


//start parse_decl_defs
/*
27 warnings that we ignore, because we want greedy matching.

NB the 'once' parameter in the code is taken care of by the caller, who will use parse_decl_def
if once=true, and use parse_decl_defs if once=false
this guy gets 16 warnings. They all stem from the fact that we could either:
do another loop into parse_decl_def
exit (conditional_declaration (parse_block (parse_decl_defs))) and then enter parse_decl_def
we want the 1st option, the greedy one that Antlr chooses by default
essentially, one of my subrules, conditional_declaration, contains parse_decl_defs within it, and
there are no tokens after parse_decl_defs. So it could exit the inner parse_decl_defs and match the outer one
if it chose to.
*/
parse_decl_defs
	:	parse_decl_def+
	;
//TODO parse_declarations and Semicolon subrules are follwed by 'continue' in DMD code
//this means parseDeclDef(once=true) would actually allow multiple of these subrules
//my parser currently does not
//I think this may be a bug, at least for the parse_declarations. Multiple semicolons in a row may not be a big deal.
//TODO if unrelated rules are pruned, do I still need synpreds for mixin?
parse_decl_def
	:	parse_enum
	|	parse_aggregate
	|	(Static? Import)=> parse_import//resolve non-LL* decision. take this over attribute_specifier
	|	parse_template_declaration
	|	(Mixin OpenParen)=> mixin_statement //I don't understand why this synpred is necessary, but if I dont have it I get error. Decision can match input such as "Mixin" using multiple alternatives: 5, 6. Then some crazy shit about "The following alternatives can never be matched: 6,14,15,16"
	|	parse_mixin
	|	(basic_type | Alias | Typedef | Identifier | Typeof | Dot)=> parse_declarations
	|	parse_ctor
	|	parse_dtor
	|	parse_invariant
	|	parse_unit_test
	|	parse_new
	|	parse_delete
//TODO EOF or CloseCurly returns from decl defs
	|	parse_static_ctor
	|	parse_static_dtor
	|	parse_static_assert
	|	attribute_specifier
	|	conditional_declaration
	|	Semicolon
	;
//end parse_decl_defs

/*Decision can match input such as "Else" using multiple alternatives: 1, 2
*/
conditional_declaration
	:	Debug Assign (Identifier | IntegerLiteral) Semicolon
	|	Version Assign (Identifier | IntegerLiteral) Semicolon
	|	(parse_debug_condition | parse_static_if_condition | parse_version_condition) 
		parse_block (Else parse_block)?
	;

//start attribute_specifier
/*Decision can match input such as "{Abstract, Auto, Const, Deprecated, Extern, Final, Override, Scope, Static, Synchronized}" using multiple alternatives: 1, 2
It's really just talking about Static matching multiple ways. Antlr does the right thing, greedy.
Decision can match input such as "Extern" using multiple alternatives. OK
Decision can match input such as "Static" using multiple alternatives. OK
Decision can match input such as "{Export, Package, Private..Public}" using multiple alternatives. OK
*/
attribute_specifier
	:	(auto_storage_class+ | Extern parse_linkage | protection_attribute+ | align_attribute | pragma_attribute) parse_block
	|	(auto_storage_class+ Identifier Assign)=> attribute_auto//needed because auto_storage_class can loop forever
	;

//the parse_block at the end is required, because parse_block leads to Semicolon
pragma_attribute
	:	Pragma OpenParen Identifier (Comma parse_arguments_required)? CloseParen
	;

//TODO I don't think DMD would allow an unsigned integer here? but i have integer literal
align_attribute
	:	Align (OpenParen IntegerLiteral CloseParen)?
	;

////is sublty different from auto_declaration. This doesn't allow an embedded Extern parse_linkage
attribute_auto
	:	auto_storage_class+ Identifier Assign parse_initializer 
		(Comma Identifier Assign parse_initializer)* Semicolon
	;

protection_attribute
	:	Private|Package|Protected|Public|Export
	;
//end attribute_specifier

//the synpred in front of parse_decl_def seems to work fine
parse_block
	:	OpenCurly parse_decl_defs CloseCurly
	|	Colon parse_decl_defs
	|	(~(Semicolon|EOF))=> parse_decl_def
	;

parse_static_assert
	:	Static Assert OpenParen parse_assign_expression (Comma parse_assign_expression)? CloseParen Semicolon
	;


//TODO have embedded code to ensure that Identifier is one of
//D C C++ Pascal Windows System
//and that AddAdd is only present if the identifier is C
parse_linkage
	:	OpenParen (Identifier AddAdd?)? CloseParen
	;


/*Doesn't quite do what DMD does, we consume the Debug token here, instead of in the calling rule
[fatal] rule parse_debug_condition has non-LL(*) decision due to recursive rule invocations reachable from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
I don't understand how this is not LL*, but this synpred fixes it, I think.
*/
parse_debug_condition
	:	Debug
	|	(Debug OpenParen)=> Debug OpenParen (IntegerLiteral | Identifier) CloseParen
	;

parse_version_condition
	:	Version OpenParen (IntegerLiteral | Identifier) CloseParen
	;

parse_static_if_condition
	:	Static If OpenParen parse_assign_expression CloseParen
	;

parse_ctor
	:	This parse_parameters parse_contracts
	;

parse_dtor
	:	Tilde This OpenParen CloseParen parse_contracts
	;

parse_static_ctor
	:	Static This OpenParen CloseParen parse_contracts
	;

parse_static_dtor
	:	Static Tilde This OpenParen CloseParen parse_contracts
	;

parse_invariant
	:	Invariant (OpenParen CloseParen)? parse_statement_curly
	;

parse_unit_test
	:	Unittest parse_statement_curly
	;

parse_new
	:	New parse_parameters parse_contracts
	;

parse_delete
	:	Delete parse_parameters parse_contracts
	;

//start parse parameters
parse_parameters
	:	OpenParen (parameter (Comma parameter)*)? DotDotDot? CloseParen
	;
	
parameter
	:	parameter_storage_class? parse_basic_type parse_declarator_optional_identifier (Assign parse_assign_expression)?
	;

parameter_storage_class
	:	In|Out|Inout|Ref|Lazy
	;
//end parse parameters

//start parse_enum
parse_enum
	:	Enum Identifier? (Colon parse_basic_type)? OpenCurly enum_members? CloseCurly
	|	Enum Identifier Semicolon
	;

enum_members
	:	enum_member (Comma enum_member)* Comma?
	;

enum_member
	:	Identifier (Assign parse_assign_expression)?
	;
//end parse_enum

//start parse_aggregate
parse_aggregate
	:	(Struct|Union|Class|Interface) Identifier Semicolon
	|	(Class|Interface) Identifier (Colon parse_base_classes)? OpenCurly parse_decl_defs CloseCurly
	|	(Struct|Union) Identifier? OpenCurly parse_decl_defs CloseCurly
	;

//start parse_base_classes
//although it doesn't make sense to have more than one protection, dmd's parser allows it
parse_base_classes
	:	base_class (Comma base_class)*
	;
base_class
	:	base_class_protection* Identifier
	;

base_class_protection
	:	(Private|Package|Protected|Public)
	;
//end parse_base_classes

parse_template_declaration
	:	Template Identifier parse_template_parameter_list OpenCurly parse_decl_defs CloseCurly
	;

//start parse_template_parameter_list
parse_template_parameter_list
	:	OpenParen (template_parameter (Comma template_parameter)*)? CloseParen
	;

template_parameter
	:	alias_parameter
	|	type_parameter
	|	tuple_parameter
	|	value_parameter
	;

alias_parameter
	:	Alias Identifier (Colon parse_basic_type parse_declarator)? (Assign parse_basic_type parse_declarator)?
	;

type_parameter
	:	Identifier (Colon parse_basic_type parse_declarator)? (Assign parse_basic_type parse_declarator)?
	;

tuple_parameter
	:	Identifier DotDotDot
	;

value_parameter
	:	parse_basic_type parse_declarator_identifier (Colon parse_cond_expression)?  (Assign parse_cond_expression)?
	;
//end parse_template_parameter_list

//start parse_mixin
parse_mixin
	:	Mixin Dot template_identifiers Identifier? Semicolon
	|	Mixin (Typeof OpenParen parse_expression CloseParen Dot Identifier)? template_identifiers Identifier? Semicolon
	;

template_identifiers
	:	template_identifier (Dot template_identifier)*
	;

template_identifier
	:	 Identifier (Not parse_template_argument_list)? 
	;
//start parse_mixin

//this appears as an alternative to the call to parse_mixin
mixin_declaration
	:	Mixin OpenParen parse_assign_expression CloseParen Semicolon
	;

//start parse_template_argument_list
parse_template_argument_list
	:	OpenParen (template_argument (Comma template_argument)*)? CloseParen
	;

/*Decision can match input such as "Dot" using multiple alternatives: 1, 2
Decision can match input such as "Identifier" using multiple alternatives: 1, 2
Decision can match input such as "Typeof" using multiple alternatives: 1, 2
Decision can match input such as "{Bool, Byte, Cdouble, Cfloat..Char, Creal..Dchar, Double, Float, Idouble, Ifloat, Int, Ireal, Long, Real, Short, Ubyte, Uint..Ulong, Ushort, Void, Wchar}" using multiple alternatives: 1, 2
*/
//isDeclaration no ident
template_argument
	:	(parse_basic_type parse_declarator)=> parse_basic_type parse_declarator
	|	parse_assign_expression
	;
//end parse_template_argument_list

//start parse_import
parse_import
	:	Static? Import import_list Semicolon
	;

import_list
	:	import_item (Comma import_item)*
	;

import_item
	:	import_binding (Dot Identifier)* (Colon import_binding_list)?
	;

/* Decision can match input such as "Comma Identifier" using multiple alternatives
Alternative 1 is chosen (pick the Comma Identifier in import_binding_list), that's the correct behavior.
*/
import_binding_list
	:	import_binding (Comma import_binding)*
	;
	
import_binding
	:	Identifier (Assign Identifier)?
	;
//end parse_import

//start parse_basic_type
parse_basic_type
	:	basic_type
	|	Identifier (Not parse_template_argument_list)? identifier_list?
	|	identifier_list
	|	Typeof OpenParen parse_expression CloseParen identifier_list?
	;
identifier_list
	:	(Dot Identifier (Not parse_template_argument_list)?)+
	;

basic_type
	:	Void
	|	Byte
	|	Ubyte
	|	Short
	|	Ushort
	|	Int
	|	Uint
	|	Long
	|	Ulong
	|	Float
	|	Double
	|	Real
	|	Ifloat
	|	Idouble
	|	Ireal
	|	Cfloat
	|	Cdouble
	|	Creal
	//Bit is in the code, but I don't see it in the lexer, so I don't have it here
	|	Bool
	|	Char
	|	Wchar
	|	Dchar
	;
//end parse_basic_type

//start parse_basic_type2
/*
Decision can match input such as "Multiply" using multiple alternatives: 1, 2
I think Alternative 1 is what we want (be greedy and loop through basic_type2_helper again, consuming the Multiply)

Decision can match input such as "OpenBracket" using multiple alternatives: 1, 2
This one I'm not sure about. How would parse declarator ever match the OpenBracket in
parse decl suffix, if basic_type2 consumes them all? I guess if CArrayDecl is false, then
decl suffix never tries to match the OpenBracket

Decision can match input such as "{Delegate, Function}" using multiple alternatives: 1, 2
I'm going to again guess that Alternative 1 is what we want. Be greedy and consume "Delegate" here,
instead of exiting the rule, going to declarator_identifier_templated, which then enters parse_basic_type2
*/
parse_basic_type2
	:	basic_type2_helper*
	;

//if right to left array decl is declared instead, change this rule
//isDeclaration no identifier
/*rule basic_type2_helper has non-LL(*) decision due to recursive rule invocations reachable from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
TODO here i'm not sure that my synpred is correct. DMD uses isDeclaration, and the comments indicate that only associative array declarations should match.
I'm going with a lazy man's synpred.
*/
basic_type2_helper
	:	Multiply
	|	OpenBracket 
			((parse_basic_type parse_declarator)=> parse_basic_type parse_declarator
			| parse_expression (DotDot parse_expression)?)? 
		CloseBracket  //Left to right array decl
	|	(Delegate|Function) parse_parameters
	;
//end parse_basic_type2

//start parse_declarator
/*
I split up parse_declarator into a few different types
parse_declarator means no identifier allowed
parse_declarator_optional_identifier means the identifer is optional
parse_declarator_identifier means identifier required
parse_declarator_identifier_templated means identifier required, template optional
*/
//TODO make sure the recursive calls to parse_declarator do the right thing with identifier
parse_declarator
	:	parse_basic_type2  declarator_suffixes
	;

parse_declarator_optional_identifier
	:	parse_basic_type2 
		( Identifier 
		| (OpenParen)=> OpenParen parse_declarator_optional_identifier CloseParen)? 
		declarator_suffixes
	;

parse_declarator_identifier
	:	parse_basic_type2 (Identifier | OpenParen parse_declarator_identifier CloseParen) declarator_suffixes
	;
	
parse_declarator_identifier_templated
	:	parse_basic_type2 (Identifier | OpenParen parse_declarator_identifier CloseParen) declarator_suffixes_templated
	;

//isDeclaration no identifier
/*[fatal] rule declarator_suffixes has non-LL(*) decision due to recursive rule invocations reachable from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
TODO is my synpred correct? same thing about synpred should only match associative array declarations
*/
declarator_suffixes
	:	//if def CArrayDecl
		(OpenBracket 
			( (parse_basic_type parse_declarator)=> parse_basic_type parse_declarator 
			| parse_expression)?
		CloseBracket)* parse_parameters?
	;

/*
[fatal] rule declarator_suffixes_templated has non-LL(*) decision due to recursive rule invocations reachable from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
TODO is my synpred correct? same thing about synpred should only match associative array declarations
*/
declarator_suffixes_templated
	:	//if def CArrayDecl
		//is declaration(3) called
		(OpenBracket 
			( (parse_basic_type parse_declarator)=> parse_basic_type parse_declarator 
			| parse_expression)? 
		CloseBracket)*
		( (parse_template_parameter_list OpenParen)=> parse_template_parameter_list parse_parameters
		|  parse_parameters)? //There used to be a synpred for this alt /*(OpenParen)=>*/
		
	;
//end parse_declarator

//start parse_declarations
/*
TODO? DMD catches the case where multiple parse_declarator are of differing types
*/
parse_declarations
	:	standard_declaration
	|	typedef_declaration
	|	alias_declaration
	//TODO I think DMD allows Extern parse_linkage in the stcs of auto decl, as long as another storage class is provided
	|	(Typedef|Alias)? auto_declaration
	|	class_declaration
	;
	
//TODO check for redundant storage class
declaration_storage_class
	:	auto_storage_class | Extern parse_linkage
	;
	
standard_declaration
	:	declaration_storage_class* parse_basic_type parse_basic_type2 
		parse_declarator_identifier_templated (Assign parse_initializer)? 
		(Comma parse_declarator_identifier_templated (Assign parse_initializer)?)* Semicolon
	;

/*NB
parse declarations will never enter this branch:	 else if (t->ty == Tfunction)
parse basic type 2() never returns Tfunction
These lines ensure that Tfunction is never returned
	if (save == TOKdelegate)
		t = new TypeDelegate(t);
	else
		t = new TypePointer(t);	// pointer to function
*/
//function_declaration	:	declaration_storage_class* parse_basic_type parse_basic_type2 /*parse_declarator_function*/ parse_contracts;

typedef_declaration
	:	Typedef declaration_storage_class* parse_basic_type parse_basic_type2 
		parse_declarator_identifier_templated (Assign parse_initializer)? 
		(Comma parse_declarator_identifier_templated (Assign parse_initializer)?)* Semicolon
	;
	
alias_declaration
	:	Alias declaration_storage_class* parse_basic_type parse_basic_type2 
		parse_declarator_identifier_templated (Comma parse_declarator_identifier_templated)* Semicolon
	;

class_declaration
	:	(Typedef|Alias)? declaration_storage_class* (Class)=> parse_aggregate
	;


auto_declaration
	:	auto_storage_class+ Identifier Assign parse_initializer 
		(Comma Identifier Assign parse_initializer)* Semicolon
	;

//TODO check for redundant storage class
auto_storage_class
	:	Const|Static|Final|Auto|Scope|Override|Abstract|Synchronized|Deprecated|Extern
	;
//end parse_declarations

//start parse_contracts
parse_contracts
	:	(OpenCurly)=> parse_statement_semi
	|	in_out_contract? Body parse_statement_curly
	|	Semicolon
	;

in_out_contract
	:	in_contract out_contract?
	|	out_contract in_contract?
	;

in_contract
	:	In parse_statement_curly
	;
	
out_contract
	:	Out (OpenParen Identifier CloseParen)? parse_statement_curly
	;
//end parse_contracts

//start parse_initializer
/*
Decision can match input such as "OpenBracket" using multiple alternatives: 2, 4
As a result, alternative(s) 4 were disabled for that input
MimicParser.g:555:2: Decision can match input such as "Void" using multiple alternatives: 3, 4
As a result, alternative(s) 4 were disabled for that input
MimicParser.g:555:2: Decision can match input such as "OpenCurly" using multiple alternatives: 1, 4
As a result, alternative(s) 4 were disabled for that input
*/
parse_initializer
	:	(OpenCurly)=> struct_initializer
	|	(OpenBracket)=> array_initializer
	|	(Void (Semicolon|Comma))=> Void (Semicolon|Comma)
	|	parse_assign_expression
	;

array_initializer
	:	OpenBracket
		Comma* (array_initializer_helper (Comma+ array_initializer_helper)* Comma*)
		CloseBracket
	;

array_initializer_helper
	:	parse_assign_expression (Colon parse_initializer)?
	|	(OpenCurly|OpenBracket)=> parse_initializer
	;

/*TODO check that Identifier that is not followed by Colon should not be consumed by initializer label!
TODO here
MimicParser.g:597:11: Decision can match input such as "Identifier" using multiple alternatives: 1, 2
MimicParser.g:597:56: Decision can match input such as "Identifier" using multiple alternatives: 1, 2
*/
struct_initializer
	:	OpenCurly
		Comma* 
		(initializer_label? parse_initializer 
			(Comma+ initializer_label? parse_initializer)* Comma*)?
		CloseCurly
	;

initializer_label
	:	Identifier Colon
	;
//end parse_initializer


//start parse_statement
/*
TODO there are several errors about what alternative to match. I'm not currently sure if they should be choosing declaration or expression statement. Fix/verify
the one about matching Identifier multiple ways is fine.
*/
//TODO OpenCurly parse_statement_semi+ (CloseCurly|EOF) is odd. check if it really works in DMD. maybe report error to walter. it also appears in other rule, search for it
//isDeclaration identifier required before Dot Typeof Identifier(fallthrough)
parse_statement
	:	(Identifier Colon)=> labeled_statement //Decision can match input such as "Identifier" using multiple alternatives
	|	declaration_statement
	|	expression_statement
	|	(Static If | Version | Debug)=> conditional_statement //Decision can match input such as "Static" using multiple alternatives: 2, 4, 5
	|	(Static Assert)=> parse_static_assert //Decision can match input such as "Static" using multiple alternatives: 2, 4, 5
	|	(Struct|Union|Class|Interface)=> parse_aggregate //synpred to prevent declaration_statment from matching, which leads to class declaration
	|	parse_enum
	|	(Mixin OpenParen)=> mixin_statement //I don't understand why this synpred is necessary, but if I dont have it I get error. Decision can match input such as "Mixin" using multiple alternatives: 8, 9. The following alternatives can never be matched: 9
	|	(Mixin)=> parse_mixin//NB must appear after mixin_statement TODO uncreachable? assert that is reachable
	|	(OpenCurly) => OpenCurly parse_statement_semi* (CloseCurly|EOF)//[fatal] rule parse_statement has non-LL(*) decision due to recursive rule invocations reachable from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
	|	while_statement
	//a semicolon by itself is not allowed, use parse_statement_semiXXX for that
	|	do_statement
	|	for_statement
	|	foreach_statement
	|	if_statement
	|	(Scope OpenParen)=> scope_guard_statement //Decision can match input such as "Scope" using multiple alternatives: 2, 16
	|	pragma_statement
	|	switch_statement
	|	case_statement
	|	default_statement
	|	return_statement
	|	break_statement
	|	continue_statement
	|	goto_statement
	|	(Synchronized)=> synchronized_statement //Synchronized should not lead to declaration_statement
	|	with_statement
	|	try_statement
	|	throw_statement
	|	volatile_statement
	|	asm_statement
	;

//curlyscope has no parser implications, it only means: if you see {}, that's a new scope
//semi_curlyscope now uses this
parse_statement_semi
	:	Semicolon
	|	parse_statement
	;

//curly_scope use this now
/*DMD allows parseStatement to match just the OpenCurly and CloseCurly
because my parse_statement does not know it's being called by parse_statement_curly,
it assumes it has to match something. So I make the parse_statement match optional
when it appears here inside the OpenCurly and CloseCurly
*/
parse_statement_curly
	:	OpenCurly parse_statement? CloseCurly
	;

//I do not separate out labels as DMD does. 
//It seems DMD doesn't allow labels that are keywords
/*
ST rule that creates the bad C# code
bitset(name, words64) ::= <<
public static readonly BitSet <name> = new BitSet(new ulong[]{<words64:{<it>UL};separator=",">});<\n>
>>
which is instantiated here and only here
<if(bitsets)>
	#region Follow sets
	private static class Follow
	{
		<bitsets:bitset(name={_<it.name>_in_<it.inName><it.tokenIndex>},
							words64=it.bits)>
	}
	#endregion Follow sets<\n>
<endif>

so let's look and see how bitsets is created

genericParser(grammar, name, scopes, tokens, tokenNames, rules, numRules,
              bitsets, inputStreamType, superClass,
              ASTLabelType="object", labelType, members, rewriteElementType,
              filterMode) ::= <<
where is the string template for genericParser instantiated?
*/
asm_statement
	:	Asm OpenCurly asm_instruction* CloseCurly
	;

asm_instruction
	:	(~(CloseCurly | Semicolon | EOF)* Semicolon)
	;

volatile_statement
	:	Volatile parse_statement_semi
	;

throw_statement
	:	Throw parse_expression
	;

//Decision can match input such as "Finally" using multiple alternatives. Greedy is good
try_statement
	:	Try parse_statement (catches finally_statement? | finally_statement)
	;

finally_statement
	:	(Finally parse_statement)
	;

/*Decision can match input such as "Catch" using multiple alternatives. Greedy is good
Decision can match input such as "OpenParen" using multiple alternatives: 1, 2. Greedy is good
*/
catches	
	:	(Catch (OpenParen parse_basic_type parse_declarator CloseParen)? parse_statement)+
	;

with_statement
	:	With OpenParen parse_expression CloseParen parse_statement
	;

//Decision can match input such as "OpenParen" using multiple alternatives: 1, 2  Greedy is good
synchronized_statement
	:	Synchronized (OpenParen parse_expression CloseParen)? parse_statement
	;

goto_statement
	:	Goto (Default|Case parse_expression?|Identifier) Semicolon
	;

continue_statement
	:	Continue Identifier? Semicolon
	;

break_statement
	:	Break Identifier? Semicolon
	;

return_statement
	:	Return parse_expression? Semicolon
	;

//TODO same as below, case statement
//exit loop when you encounter (Case|Default|CloseCurly|EOF)
default_statement
	:	Default Colon ((~(Case|Default|CloseCurly|EOF))=> parse_statement_semi)*
	;

//TODO double check that my syntactic predicate exits the loop properly & matches DMD
case_statement
	:	Case parse_assign_expression (Comma parse_assign_expression)* Colon 
		((~(Case|Default|CloseCurly|EOF))=> parse_statement_semi)*
	;

switch_statement
	:	Switch OpenParen parse_expression CloseParen parse_statement
	;

pragma_statement
	:	Pragma OpenParen Identifier (Comma parse_arguments_required)? CloseParen parse_statement_semi
	;

//TODO verify that Identifier is 'exit' 'failure' success'
scope_guard_statement
	:	Scope OpenParen Identifier CloseParen parse_statement
	;

//Decision can match input such as "Else" using multiple alternatives. Antlr does the right thing.
//isDeclaration ident required
if_statement
	:	If OpenParen 
		( Auto Identifier Assign 
		| parse_basic_type parse_declarator_identifier Assign
		| Identifier (Comma|Semicolon)) 
		parse_expression CloseParen parse_statement (Else parse_statement)?
	;

//start foreach_statement
foreach_statement
	:	(Foreach|Foreach_reverse) OpenParen foreach_type_list Semicolon parse_expression CloseParen parse_statement
	;

foreach_type_list
	:	foreach_type (Comma foreach_type)*
	;

foreach_type
	:	(Inout|Ref)? (parse_basic_type parse_declarator_identifier | /*(Identifier (Comma | Semicolon))=>*/ Identifier)
	;
//end foreach_statement

for_statement
	:	For OpenParen (parse_statement|Semicolon) (parse_expression? Semicolon) 
		parse_expression? CloseParen parse_statement
	;

do_statement
	:	Do parse_statement While OpenParen parse_expression CloseParen
	;

while_statement
	:	While OpenParen parse_expression CloseParen parse_statement
	;

mixin_statement
	:	Mixin OpenParen parse_assign_expression CloseParen Semicolon
	;

declaration_statement_predicate
	:	Identifier ~(Colon)
	;
/*
Decision can match input such as "Else" using multiple alternatives
The right thing is done by default. Greedily match the Else to the closest If
preceeding it, as opposed to the outer nesting If taking the Else.
*/
conditional_statement
	:	(parse_static_if_condition | parse_version_condition | parse_debug_condition) 
		parse_statement (Else parse_statement)?
	;

expression_statement
	:	/*(Identifier|Dot|Typeof|a bunch of other shit)*/ parse_expression Semicolon
	;

declaration_statement
	:	/*(Identifier|Dot|Typeof|Static|other shit perhaps search for goto Ldeclaration)*/ parse_declarations
	;

labeled_statement
	:	Identifier Colon parse_statement_semi
	;
//end parse_statement

//All the expressions folow

//start parse_primary_expression
//TODO DMD checks for matching string postfixes as it concatenates them together. I should do this too.
/*Decision can match input such as "StringLiteral" using multiple alternatives: 1, 2  Greedy is good (i'm pretty sure this case is fine. I didn't check in detail)

This is no longer of concern due to refactoring of function_literal
These refer to alt 22, function_literal's parse_contracts alternative. Since it is preceeded
by a syntactic predicate (OpenCurly)=> we can ignore these warnings, none of which mention OpenCurly.
Simply put- we only want function_literal, parse_contracts if it starts with an OpenCurly
*/
parse_primary_expression
	:	(Identifier (Not parse_template_argument_list)? 
		| Dollar
		| Dot
		| This
		| Super
		| IntegerLiteral
		| FloatLiteral
		| Null
		| True
		| False
		| CharacterLiteral
		| StringLiteral+
		| basic_type Dot Identifier
		| Typeof OpenParen parse_expression CloseParen
		| Typeid OpenParen parse_basic_type parse_declarator CloseParen
		| is_expression
		| Assert OpenParen parse_assign_expression (Comma parse_assign_expression)? CloseParen
		| Mixin OpenParen parse_assign_expression CloseParen
		| Import OpenParen parse_assign_expression CloseParen
		| OpenParen parse_expression CloseParen
		| array_or_assoc_array_literal
	//TODO OpenCurly  I'm not sure parse primary is finished with regards to this token. Check that last alt of function_literal is correct
		| function_literal
	) parse_post_expression	
	;
/*
I was getting mutual left recusrion, with the rule invocations going in this order:

parse primary expression
function literal
parse contracts
parse statement semi
parse statement
expression statement
parse expression
parse assign expression
parse cond expression ... oror andand or xor and equal rel shift add mul unary
parse primray expression - This takes us back to the top again.

Function literal will only call parse contracts if the predicate matches OpenCurly. 
parse statement consumes OpenCurly. Thus the mutual left recursion is broken.

My solution is to copy the part of parse_statement that consumes OpenCurly into function_literal.
Function literal no longer call parse_contracts.
TODO double check that this transformation is correct.
*/
function_literal
	:	(Function | Delegate) 
		( (OpenCurly)=> parse_contracts 
		| (parse_basic_type parse_basic_type2)? parse_parameters parse_contracts)
	|	(parse_parameters OpenCurly)=> parse_parameters parse_contracts
	|	OpenCurly parse_statement_semi* (CloseCurly|EOF) //TODO really? EOF? this also appears in another rule
	;
//end parse_primary_expression

//start array_or_assoc_array_literal
//69 warnings without the synpred
array_or_assoc_array_literal
	:	 OpenBracket ((associative_array_literal)=> associative_array_literals | array_literals)? CloseBracket
	;

associative_array_literals
	:	associative_array_literal (Comma associative_array_literal)*
	;

associative_array_literal
	:	parse_assign_expression Colon parse_assign_expression
	;

array_literals
	:	parse_assign_expression (Comma parse_assign_expression)*
	;
//end array_or_assoc_array_literal

//start is_expression
is_expression
	:	Is OpenParen parse_basic_type parse_declarator
		( Colon parse_basic_type parse_declarator
		| EqualEqual type_specialization)
		CloseParen
	;

type_specialization
	:	Typedef|Struct|Union|Class|Super|Enum|Interface|Function|Delegate|Return
	;
//end is_expression

//start parse_post_expression
/*
Greedy is good. Antlr does the right thing for all of these.
Decision can match input such as "OpenParen" using multiple alternatives: 4, 6
Decision can match input such as "OpenBracket" using multiple alternatives: 5, 6
Decision can match input such as "Dot" using multiple alternatives: 1, 6
Decision can match input such as "Not" using multiple alternatives: 1, 2
Decision can match input such as "AddAdd" using multiple alternatives: 2, 6
Decision can match input such as "SubtractSubtract" using multiple alternatives: 3, 6
*/
parse_post_expression
	:	( Dot (Identifier (Not parse_template_argument_list)? | parse_new_expression)
		| AddAdd
		| SubtractSubtract
		| OpenParen parse_arguments CloseParen
		| index_or_slice_expression
		)*
	;

//start index_or_slice_expression
//this synpred fixes 69 warnings
index_or_slice_expression
	:	 OpenBracket ((parse_assign_expression DotDot)=> slice_expression | index_expression)? CloseBracket
	;

index_expression
	:	parse_assign_expression (Comma parse_assign_expression)*
	;

slice_expression
	:	parse_assign_expression DotDot parse_assign_expression
	;
//end index_or_slice_expression

parse_unary_expression
	:	(And | AddAdd | SubtractSubtract | Multiply | Subtract | Add | Not | Tilde Delete) parse_unary_expression
	|	Cast OpenParen parse_basic_type parse_declarator CloseParen parse_unary_expression
	|	parse_new_expression
	//this seems out of place, being stuck inside #if CCASTSYNTAX. I dont think it should be inside the #if
	|	(OpenParen parse_basic_type)=> OpenParen parse_basic_type parse_declarator CloseParen Dot Identifier parse_post_expression //i dont understand why this synpred is necessary
	|	parse_primary_expression
	;

//TODO check that i've got precedence and order of operations correct
/*Decision can match input such as "Multiply" using multiple alternatives: 1, 2
Decision can match input such as "{Divide, Modulo}" using multiple alternatives: 1, 2
Greedy is good
*/
parse_mul_expression
	:	parse_unary_expression ((Multiply|Divide|Modulo) parse_unary_expression)*
	;

/*Decision can match input such as "Add" using multiple alternatives: 1, 2
Decision can match input such as "Subtract" using multiple alternatives: 1, 2
Decision can match input such as "Tilde" using multiple alternatives: 1, 2
greedy is good
*/parse_add_expression
	:	parse_mul_expression ((Add|Subtract|Tilde) parse_mul_expression)*
	;
/*Decision can match input such as "{ShiftLeft, ShiftRight..UnsignedShiftRight}" using multiple alternatives: 1, 2
greedy is good*/
parse_shift_expression
	:	parse_add_expression ((ShiftLeft|ShiftRight|UnsignedShiftRight) parse_add_expression)*
	;

/* I think all of these are fine, greedy is good.
Decision can match input such as "LessGreaterEqual" using multiple alternatives: 1, 2
Decision can match input such as "LessGreater" using multiple alternatives: 1, 2
Decision can match input such as "NotLessGreaterEqual" using multiple alternatives: 1, 2
Decision can match input such as "GreaterEqual" using multiple alternatives: 1, 2
Decision can match input such as "Greater" using multiple alternatives: 1, 2
Decision can match input such as "LessEqual" using multiple alternatives: 1, 2
Decision can match input such as "Less" using multiple alternatives: 1, 2
Decision can match input such as "In" using multiple alternatives: 1, 2
Decision can match input such as "NotLessGreater" using multiple alternatives: 1, 2
Decision can match input such as "NotLessEqual" using multiple alternatives: 1, 2
Decision can match input such as "NotLess" using multiple alternatives: 1, 2
Decision can match input such as "NotGreaterEqual" using multiple alternatives: 1, 2
Decision can match input such as "NotGreater" using multiple alternatives: 1, 2
*/
parse_rel_expression
	:	parse_shift_expression ((Less|LessEqual|Greater|GreaterEqual|NotLessGreaterEqual|LessGreater|LessGreaterEqual|NotGreater|NotGreaterEqual|NotLess|NotLessEqual|NotLessGreater|In) parse_shift_expression)*
	;
/*greedy is good
Decision can match input such as "Not" using multiple alternatives: 1, 2
Decision can match input such as "NotEqual" using multiple alternatives: 1, 2
Decision can match input such as "Is" using multiple alternatives: 1, 2
Decision can match input such as "EqualEqual" using multiple alternatives: 1, 2
*/
parse_equal_expression
	:	parse_rel_expression ((EqualEqual|NotEqual|Is|Not Is) parse_rel_expression)*
	;

//This seems to be equal and rel combined into one rule to give the same precedence
parse_cmp_expression
	:	parse_shift_expression ((EqualEqual|NotEqual|Is|Not Is|Less|LessEqual|Greater|GreaterEqual|NotLessGreaterEqual|LessGreater|LessGreaterEqual|NotGreater|NotGreaterEqual|NotLess|NotLessEqual|NotLessGreater|In) parse_shift_expression)*
	;

//if d version == 1 do it this way. dversion2, parse cmp expression instead.
/*greedy is good
Decision can match input such as "And" using multiple alternatives: 1, 2*/
parse_and_expression
	:	parse_equal_expression ((And) parse_equal_expression)*
	;

/*greedy is good
Decision can match input such as "Xor" using multiple alternatives: 1, 2
*/
parse_xor_expression
	:	parse_and_expression ((Xor) parse_and_expression)*
	;

/*Greedy is good
Decision can match input such as "Or" using multiple alternatives: 1, 2
*/
parse_or_expression
	:	parse_xor_expression ((Or) parse_xor_expression)*
	;

/*greedy is good
Decision can match input such as "AndAnd" using multiple alternatives: 1, 2*/
parse_andand_expression
	:	parse_or_expression ((AndAnd) parse_or_expression)*
	;

/*greedy is good
Decision can match input such as "OrOr" using multiple alternatives: 1, 2*/
parse_oror_expression
	:	parse_andand_expression ((OrOr) parse_andand_expression)*
	;

//why are they different? parse_expression vs parse_cond_expression
/*greedy is good
Decision can match input such as "QuestionMark" using multiple alternatives: 1, 2*/
parse_cond_expression
	:	parse_oror_expression (QuestionMark parse_expression Colon parse_cond_expression)?
	;

/*Decision can match input such as "{DivideAssign, AndAssign, OrAssign, SubtractAssign, AddAssign, ShiftLeftAssign, ShiftRightAssign..UnsignedShiftRightAssign, Assign, MultiplyAssign, ModuloAssign, XorAssign, TildeAssign}" using multiple alternatives: 1, 2
Greedy is good. It's saying you can immediately match the token, or exit this rule, and match the token
in a calling rule, which happens to be parse_assign_expression
*/
parse_assign_expression
	:	
		parse_cond_expression ((Assign|AddAssign|SubtractAssign|MultiplyAssign|DivideAssign|ModuloAssign|AndAssign|OrAssign|XorAssign|ShiftLeftAssign|ShiftRightAssign|UnsignedShiftRightAssign|TildeAssign) parse_assign_expression)*
	;

/*greedy is good
Decision can match input such as "Comma" using multiple alternatives: 1, 2
*/
parse_expression
	:	parse_assign_expression (Comma parse_assign_expression)*
	;


/*I do this slightly differently than DMD. DMD checks what the starting token was: ( or [
consumes it, and consumes the corresponding end token.
I have the caller of this rule surround the rule with the aforementioned tokens.
*/
parse_arguments
	:	parse_arguments_required?
	;

//this version requires at least one parse_assign_expression
parse_arguments_required
	:	(parse_assign_expression (Comma parse_assign_expression)*)
	;

/*part of this code is controlled by #if LTORARRAYDECL
I will probably differ from DMD here, because it looks like it does some semantic analysis
to generate an error saying "need size of rightmost array, not type %s"

Decision can match input such as "OpenParen" using multiple alternatives: 1, 2
greedy is good
*/
parse_new_expression
	:	New
		(Class (OpenParen parse_arguments CloseParen)? parse_base_classes? OpenCurly parse_decl_defs CloseCurly)?
		parse_basic_type parse_basic_type2 (OpenParen parse_arguments CloseParen)?
	;
